import hashlib
import base64
import re

from Crypto.Cipher import AES
from odoo.exceptions import ValidationError
from math import ceil


class SignTools:

    def __init__(self):
        pass

    # AES加密
    def aes_encode(self, d, key, iv):
        try:
            # PKCS7填充
            data = d.encode('utf-8')
            pl = 16 - (len(data) % 16)
            data = data + bytearray([pl for i in range(pl)])
            # AES加密
            aes_obj = AES.new(key.encode('utf-8'), AES.MODE_CBC, iv.encode('utf-8'))
            encoded_data = base64.b64encode(aes_obj.encrypt(data)).decode('utf-8')
            return encoded_data
        except Exception:
            raise ValidationError('AES加密出错')

    # AES解密
    def aes_decode(self, d, key, iv):
        try:
            data = base64.b64decode(d.encode('utf-8'))
            aes_obj = AES.new(key.encode('utf-8'), AES.MODE_CBC, iv.encode('utf-8'))
            decoded_data = aes_obj.decrypt(data).strip().decode('utf-8')
            return re.sub(
                '[\001\002\003\004\005\006\007\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a]+',
                '', decoded_data)
        except Exception:
            raise ValidationError('AES解密出错')

    # SHA256加密
    def sha256_encode(self, data):
        try:
            encoded_data = hashlib.sha256(data.encode('utf-8')).hexdigest()
            return encoded_data
        except Exception:
            raise ValidationError('SHA256加密出错')

    # md5加密
    def md5_encode(self, data):
        encoded_data = hashlib.md5(data.encode('utf-8')).hexdigest()
        return encoded_data

    # sign签名算法
    def get_signed_params(self, params, sign):
        # 根据参数名称字母顺序进行排序
        sorted_params = sorted(params.items(), key=lambda x: x[0])
        # 拼接参数名与参数值 以及 signkey
        combined_params = ''
        for key, value in dict(sorted_params).items():
            combined_params += str(key)
            combined_params += str(value)
        combined_params += sign
        # 返回md5加密的值
        return md5_encode(combined_params)

    # 分割列表方法（原列表、固定长度）
    def chunk(self, lst, size):
        return list(
            map(lambda x: lst[x * size:x * size + size],
                list(range(0, ceil(len(lst) / size)))))
